module TLB #(
    parameter ADDR_WIDTH = 64,
    parameter PPN_WIDTH = 44,
    parameter PAGE_SIZE = 4096,
    parameter TLB_SIZE = 32
) (
    input wire clk,
    input wire rst,
    input wire [ADDR_WIDTH-1:0] virt_addr,
    input wire [ADDR_WIDTH-1:0] in_phys_addr,
    input wire update,
    input wire tlb_flush,
    output wire [ADDR_WIDTH-1:0] out_phys_addr,
    output wire hit
);

    // TLB Entry structure
    typedef struct {
        reg [21:0] tag;
        reg [43:0] ppn;
        reg valid;
        reg lru;
    } TlbLine_t;
    
    TlbLine_t index_line [1:0];
    TlbLine_t set [1:0][31:0]; // 32 entries

    wire set_line = index_line[0].lru;
    wire hit_set  = tlb_hit[1]; // tlb_hit[1] ? 1:0
    
    assign index_line[0] = set[0][virt_index];
    assign index_line[1] = set[1][virt_index];

    wire [21:0] virt_tag = virt_addr[38:17];
    wire [4:0] virt_index = virt_addr[16:12];
    wire [11:0] virt_offset = virt_addr[11:0];
    wire [43:0] phys_ppn = in_phys_addr[55:12];

    wire [1:0] tlb_hit;
    assign tlb_hit[0] = index_line[0].valid & (index_line[0].tag==virt_tag);
    assign tlb_hit[1] = index_line[1].valid & (index_line[1].tag==virt_tag);

    assign hit = tlb_hit[0] | tlb_hit[1];
    assign out_phys_addr = hit ? {8'b0,index_line[hit_set].ppn,virt_offset} : 0;
    
    // TLB update
    always @(posedge clk or posedge rst) begin
        if (rst | tlb_flush) begin
            integer i;
            for (i = 0; i < TLB_SIZE; i = i + 1) begin
                set[0][i].valid <= 0;
                set[0][i].lru <= 0;
                set[1][i].valid <= 0;
                set[1][i].lru <= 0;
            end
        end else if (update&~hit) begin
            set[set_line][virt_index].tag <= virt_tag;
            set[set_line][virt_index].ppn <= phys_ppn;
            set[set_line][virt_index].valid <= 1'b1;
            set[0][virt_index].lru <= ~set_line;
            
        end
        else if(~tlb_hit[0]) begin // 0 没命中下次就换 0
            set[0][virt_index].lru <= 0;
        end
    end

endmodule
